home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 16 / AMIGAplus Sonderheft 16 (1998)(ICP)(DE)[!].iso / pd / anwendungen / ispell-3.1.18src / buildhash.c < prev    next >
C/C++ Source or Header  |  1995-07-03  |  17KB  |  692 lines

  1. #ifndef lint
  2. static char Rcs_Id[] =
  3.     "$Id: buildhash.c,v 1.64 1995/01/08 23:23:26 geoff Exp $";
  4. #endif
  5.  
  6. #define MAIN
  7.  
  8. /*
  9.  * buildhash.c - make a hash table for okspell
  10.  *
  11.  * Pace Willisson, 1983
  12.  *
  13.  * Copyright 1992, 1993, Geoff Kuenning, Granada Hills, CA
  14.  * All rights reserved.
  15.  *
  16.  * Redistribution and use in source and binary forms, with or without
  17.  * modification, are permitted provided that the following conditions
  18.  * are met:
  19.  *
  20.  * 1. Redistributions of source code must retain the above copyright
  21.  *    notice, this list of conditions and the following disclaimer.
  22.  * 2. Redistributions in binary form must reproduce the above copyright
  23.  *    notice, this list of conditions and the following disclaimer in the
  24.  *    documentation and/or other materials provided with the distribution.
  25.  * 3. All modifications to the source code must be clearly marked as
  26.  *    such.  Binary redistributions based on modified source code
  27.  *    must be clearly marked as modified versions in the documentation
  28.  *    and/or other materials provided with the distribution.
  29.  * 4. All advertising materials mentioning features or use of this software
  30.  *    must display the following acknowledgment:
  31.  *      This product includes software developed by Geoff Kuenning and
  32.  *      other unpaid contributors.
  33.  * 5. The name of Geoff Kuenning may not be used to endorse or promote
  34.  *    products derived from this software without specific prior
  35.  *    written permission.
  36.  *
  37.  * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
  38.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  39.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  40.  * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
  41.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  42.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  43.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  44.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  45.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  46.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47.  * SUCH DAMAGE.
  48.  */
  49.  
  50. /*
  51.  * $Log: buildhash.c,v $
  52.  * Revision 1.64  1995/01/08  23:23:26  geoff
  53.  * Make the various file suffixes configurable for DOS purposes.
  54.  *
  55.  * Revision 1.63  1994/10/26  05:12:25  geoff
  56.  * Get rid of some duplicate declarations.
  57.  *
  58.  * Revision 1.62  1994/07/28  05:11:33  geoff
  59.  * Log message for previous revision: distinguish a zero count from a bad
  60.  * count file.
  61.  *
  62.  * Revision 1.61  1994/07/28  04:53:30  geoff
  63.  *
  64.  * Revision 1.60  1994/01/25  07:11:18  geoff
  65.  * Get rid of all old RCS log lines in preparation for the 3.1 release.
  66.  *
  67.  */
  68.  
  69. #include "config.h"
  70. #include "ispell.h"
  71. #include "proto.h"
  72. #include "msgs.h"
  73.  
  74. #ifdef AMIGA
  75. extern char * Version_ID[];
  76. #else
  77. #include "version.h"
  78. #endif
  79.  
  80. #include <ctype.h>
  81. #include <sys/stat.h>
  82.  
  83. int        main P ((int argc, char * argv[]));
  84. static void    output P ((void));
  85. static void    filltable P ((void));
  86. VOID *        mymalloc P ((unsigned int size));
  87. VOID *        myrealloc P ((VOID * ptr, unsigned int size,
  88.           unsigned int oldsize));
  89. void        myfree P ((VOID * ptr));
  90. static void    readdict P ((void));
  91. static void    newcount P ((void));
  92.  
  93. #define NSTAT    100        /* Size probe-statistics table */
  94.  
  95. struct stat    dstat;        /* Result of stat-ing dict file */
  96. struct stat    cstat;        /* Result of stat-ing count file */
  97.  
  98. char *        Dfile;        /* Name of dictionary file */
  99. char *        Hfile;        /* Name of hash (output) file */
  100. char *        Lfile;        /* Name of language file */
  101.  
  102. char        Cfile[MAXPATHLEN]; /* Name of count file */
  103. char        Sfile[MAXPATHLEN]; /* Name of statistics file */
  104.  
  105. static int silent = 0;        /* NZ to suppress count reports */
  106.  
  107. int main (argc, argv)
  108.     int        argc;
  109.     char *    argv[];
  110.     {
  111.     int        avg;
  112.     FILE *    countf;
  113.     FILE *    statf;
  114.     int        stats[NSTAT];
  115.     int        i;
  116.     int        j;
  117.  
  118.     while (argc > 1  &&  *argv[1] == '-')
  119.     {
  120.     argc--;
  121.     argv++;
  122.     switch (argv[0][1])
  123.         {
  124.         case 's':
  125.         silent = 1;
  126.         break;
  127.         }
  128.     }
  129.     if (argc == 4)
  130.     {
  131.     Dfile = argv[1];
  132.     Lfile = argv[2];
  133.     Hfile = argv[3];
  134.     }
  135.     else
  136.     {
  137.     (void) fprintf (stderr, BHASH_C_USAGE);
  138.     return 1;
  139.     }
  140.  
  141.     if (yyopen (Lfile))            /* Open the language file */
  142.     return 1;
  143.     yyinit ();                /* Set up for the parse */
  144.     if (yyparse ())            /* Parse the language tables */
  145.     exit (1);
  146.  
  147.     (void) sprintf (Cfile, "%s%s", Dfile, COUNTSUFFIX);
  148.     (void) sprintf (Sfile, "%s%s", Dfile, STATSUFFIX);
  149.  
  150.     if (stat (Dfile, &dstat) < 0)
  151.     {
  152.     (void) fprintf (stderr, BHASH_C_NO_DICT, Dfile);
  153.         exit (1);
  154.     }
  155.     if (stat (Cfile, &cstat) < 0 || dstat.st_mtime > cstat.st_mtime)
  156.     newcount ();
  157.  
  158.     if ((countf = fopen (Cfile, "r")) == NULL)
  159.     {
  160.     (void) fprintf (stderr, BHASH_C_NO_COUNT);
  161.     exit (1);
  162.     }
  163.     hashsize = 0;
  164.     if (fscanf (countf, "%d", &hashsize) != 1  ||  fclose (countf) == EOF)
  165.     {
  166.     (void) fprintf (stderr, BHASH_C_BAD_COUNT);
  167.     exit (1);
  168.     }
  169.     if (hashsize == 0)
  170.     {
  171.     (void) fprintf (stderr, BHASH_C_ZERO_COUNT);
  172.     exit (1);
  173.     }
  174.     readdict ();
  175.  
  176.     if ((statf = fopen (Sfile, "w")) == NULL)
  177.     {
  178.     (void) fprintf (stderr, CANT_CREATE, Sfile);
  179.     exit (1);
  180.     }
  181.  
  182.     for (i = 0; i < NSTAT; i++)
  183.     stats[i] = 0;
  184.     for (i = 0; i < hashsize; i++)
  185.     {
  186.     struct dent *   dp;
  187.  
  188.     dp = &hashtbl[i];
  189.     if ((dp->flagfield & USED) != 0)
  190.         {
  191.         for (j = 0;  dp != NULL;  j++, dp = dp->next)
  192.         {
  193.         if (j >= NSTAT)
  194.             j = NSTAT - 1;
  195.         stats[j]++;
  196.         }
  197.         }
  198.     }
  199.     for (i = 0, j = 0, avg = 0;  i < NSTAT;  i++)
  200.     {
  201.     j += stats[i];
  202.     avg += stats[i] * (i + 1);
  203.     if (j == 0)
  204.         (void) fprintf (statf, "%d:\t%d\t0\t0.0\n", i + 1, stats[i]);
  205.     else
  206.         (void) fprintf (statf, "%d:\t%d\t%d\t%f\n", i + 1, stats[i], j,
  207.           (double) avg / j);
  208.     }
  209.     (void) fclose (statf);
  210.  
  211.     filltable ();
  212.     output ();
  213.     return 0;
  214.     }
  215.  
  216. static void output ()
  217.     {
  218.     register FILE *        houtfile;
  219.     register struct dent *    dp;
  220.     int                strptr;
  221.     int                n;
  222.     int                i;
  223.     int                maxplen;
  224.     int                maxslen;
  225.     struct flagent *        fentry;
  226.  
  227.     if ((houtfile = fopen (Hfile, "wb")) == NULL)
  228.     {
  229.     (void) fprintf (stderr, CANT_CREATE, Hfile);
  230.     return;
  231.     }
  232.     hashheader.stringsize = 0;
  233.     hashheader.lstringsize = 0;
  234.     hashheader.tblsize = hashsize;
  235.     (void) fwrite ((char *) &hashheader, sizeof hashheader, 1, houtfile);
  236.     strptr = 0;
  237.     /*
  238.     ** Put out the strings from the flags table.  This code assumes that
  239.     ** the size of the hash header is a multiple of the size of ichar_t,
  240.     ** and that any integer can be converted to an (ichar_t *) and back
  241.     ** without damage.
  242.     */
  243.     maxslen = 0;
  244.     for (i = numsflags, fentry = sflaglist;  --i >= 0;  fentry++)
  245.     {
  246.     if (fentry->stripl)
  247.         {
  248.         (void) fwrite ((char *) fentry->strip, fentry->stripl + 1,
  249.           sizeof (ichar_t), houtfile);
  250.         fentry->strip = (ichar_t *) strptr;
  251.         strptr += (fentry->stripl + 1) * sizeof (ichar_t);
  252.         }
  253.     if (fentry->affl)
  254.         {
  255.         (void) fwrite ((char *) fentry->affix, fentry->affl + 1,
  256.           sizeof (ichar_t), houtfile);
  257.         fentry->affix = (ichar_t *) strptr;
  258.         strptr += (fentry->affl + 1) * sizeof (ichar_t);
  259.         }
  260.     n = fentry->affl - fentry->stripl;
  261.     if (n < 0)
  262.         n = -n;
  263.     if (n > maxslen)
  264.         maxslen = n;
  265.     }
  266.     maxplen = 0;
  267.     for (i = numpflags, fentry = pflaglist;  --i >= 0;  fentry++)
  268.     {
  269.     if (fentry->stripl)
  270.         {
  271.         (void) fwrite ((char *) fentry->strip, fentry->stripl + 1,
  272.           sizeof (ichar_t), houtfile);
  273.         fentry->strip = (ichar_t *) strptr;
  274.         strptr += (fentry->stripl + 1) * sizeof (ichar_t);
  275.         }
  276.     if (fentry->affl)
  277.         {
  278.         (void) fwrite ((char *) fentry->affix, fentry->affl + 1,
  279.           sizeof (ichar_t), houtfile);
  280.         fentry->affix = (ichar_t *) strptr;
  281.         strptr += (fentry->affl + 1) * sizeof (ichar_t);
  282.         }
  283.     n = fentry->affl - fentry->stripl;
  284.     if (n < 0)
  285.         n = -n;
  286.     if (n > maxplen)
  287.         maxplen = n;
  288.     }
  289.     /*
  290.     ** Write out the string character type tables.
  291.     */
  292.     hashheader.strtypestart = strptr;
  293.     for (i = 0;  i < hashheader.nstrchartype;  i++)
  294.     {
  295.     n = strlen (chartypes[i].name) + 1;
  296.     (void) fwrite (chartypes[i].name, n, 1, houtfile);
  297.     strptr += n;
  298.     n = strlen (chartypes[i].deformatter) + 1;
  299.     (void) fwrite (chartypes[i].deformatter, n, 1, houtfile);
  300.     strptr += n;
  301.     for (n = 0;
  302.       chartypes[i].suffixes[n] != '\0';
  303.       n += strlen (&chartypes[i].suffixes[n]) + 1)
  304.         ;
  305.     n++;
  306.     (void) fwrite (chartypes[i].suffixes, n, 1, houtfile);
  307.     strptr += n;
  308.     }
  309.     hashheader.lstringsize = strptr;
  310.     /* We allow one extra byte because missingletter() may add one byte */
  311.     maxslen += maxplen + 1;
  312.     if (maxslen > MAXAFFIXLEN)
  313.     {
  314.     (void) fprintf (stderr,
  315.       BHASH_C_BAFF_1 (MAXAFFIXLEN, maxslen - MAXAFFIXLEN));
  316.     (void) fprintf (stderr, BHASH_C_BAFF_2);
  317.     }
  318.     /* Put out the dictionary strings */
  319.     for (i = 0, dp = hashtbl;  i < hashsize;  i++, dp++)
  320.     {
  321.     if (dp->word == NULL)
  322.         dp->word = (char *) -1;
  323.     else
  324.         {
  325.         n = strlen (dp->word) + 1;
  326.         (void) fwrite (dp->word, n, 1, houtfile);
  327.         dp->word = (char *) strptr;
  328.         strptr += n;
  329.         }
  330.     }
  331.     /* Pad file to a struct dent boundary for efficiency. */
  332.     n = (strptr + sizeof hashheader) % sizeof (struct dent);
  333.     if (n != 0)
  334.     {
  335.     n = sizeof (struct dent) - n;
  336.     strptr += n;
  337.     while (--n >= 0)
  338.         (void) putc ('\0', houtfile);
  339.     }
  340.     /* Put out the hash table itself */
  341.     for (i = 0, dp = hashtbl;  i < hashsize;  i++, dp++)
  342.     {
  343.     if (dp->next != 0)
  344.         {
  345.         int        x;
  346.         x = dp->next - hashtbl;
  347.         dp->next = (struct dent *)x;
  348.         }
  349.     else
  350.         {
  351.         dp->next = (struct dent *)-1;
  352.         }
  353. #ifdef PIECEMEAL_HASH_WRITES
  354.     (void) fwrite ((char *) dp, sizeof (struct dent), 1, houtfile);
  355. #endif /* PIECEMEAL_HASH_WRITES */
  356.     }
  357. #ifndef PIECEMEAL_HASH_WRITES
  358.     (void) fwrite ((char *) hashtbl, sizeof (struct dent), hashsize, houtfile);
  359. #endif /* PIECEMEAL_HASH_WRITES */
  360.     /* Put out the language tables */
  361.     (void) fwrite ((char *) sflaglist,
  362.       sizeof (struct flagent), numsflags, houtfile);
  363.     hashheader.stblsize = numsflags;
  364.     (void) fwrite ((char *) pflaglist,
  365.       sizeof (struct flagent), numpflags, houtfile);
  366.     hashheader.ptblsize = numpflags;
  367.     /* Finish filling in the hash header. */
  368.     hashheader.stringsize = strptr;
  369.     rewind (houtfile);
  370.     (void) fwrite ((char *) &hashheader, sizeof hashheader, 1, houtfile);
  371.     (void) fclose (houtfile);
  372.     }
  373.  
  374. static void filltable ()
  375.     {
  376.     struct dent *freepointer, *nextword, *dp;
  377.     struct dent *hashend;
  378.     int i;
  379.     int overflows;
  380.     
  381.     hashend = hashtbl + hashsize;
  382.     for (freepointer = hashtbl;
  383.       (freepointer->flagfield & USED)  &&  freepointer < hashend;
  384.       freepointer++)
  385.     ;
  386.     overflows = 0;
  387.     for (nextword = hashtbl, i = hashsize; i != 0; nextword++, i--)
  388.     {
  389.     if ((nextword->flagfield & USED) == 0)
  390.         continue;
  391.     if (nextword->next >= hashtbl  &&  nextword->next < hashend)
  392.         continue;
  393.     dp = nextword;
  394.     while (dp->next)
  395.         {
  396.         if (freepointer >= hashend)
  397.         {
  398.         overflows++;
  399.         break;
  400.         }
  401.         else
  402.         {
  403.         *freepointer = *(dp->next);
  404.         dp->next = freepointer;
  405.         dp = freepointer;
  406.  
  407.         while ((freepointer->flagfield & USED)
  408.           &&  freepointer < hashend)
  409.             freepointer++;
  410.         }
  411.         }
  412.     }
  413.     if (overflows)
  414.     (void) fprintf (stderr, BHASH_C_OVERFLOW, overflows);
  415.     }
  416.  
  417. #if MALLOC_INCREMENT == 0
  418. VOID * mymalloc (size)
  419.     unsigned int    size;
  420.     {
  421.  
  422.     return malloc (size);
  423.     }
  424.  
  425. /* ARGSUSED */
  426. VOID * myrealloc (ptr, size, oldsize)
  427.     VOID *        ptr;
  428.     unsigned int    size;
  429.     unsigned int    oldsize;
  430.     {
  431.  
  432.     return realloc (ptr, size);
  433.     }
  434.  
  435. void myfree (ptr)
  436.     VOID *    ptr;
  437.     {
  438.  
  439.     free (ptr);
  440.     }
  441.  
  442. #else
  443.  
  444. VOID * mymalloc (size)        /* Fast, unfree-able variant of malloc */
  445.     unsigned int    size;
  446.     {
  447.     VOID *        retval;
  448.     static int        bytesleft = 0;
  449.     static VOID *    nextspace;
  450.  
  451.     if (size < 4)
  452.     size = 4;
  453.     size = (size + 7) & ~7;    /* Assume doubleword boundaries are enough */
  454.     if (bytesleft < size)
  455.     {
  456.     bytesleft = (size < MALLOC_INCREMENT) ? MALLOC_INCREMENT : size;
  457.     nextspace = malloc ((unsigned) bytesleft);
  458.     if (nextspace == NULL)
  459.         {
  460.         bytesleft = 0;
  461.         return NULL;
  462.         }
  463.     }
  464.     retval = nextspace;
  465.     nextspace = (VOID *) ((char *) nextspace + size);
  466.     bytesleft -= size;
  467.     return retval;
  468.     }
  469.  
  470. VOID * myrealloc (ptr, size, oldsize)
  471.     VOID *        ptr;
  472.     unsigned int    size;
  473.     unsigned int    oldsize;
  474.     {
  475.     VOID *nptr;
  476.  
  477.     nptr = mymalloc (size);
  478.     if (nptr == NULL)
  479.     return NULL;
  480.     (void) bcopy (ptr, nptr, oldsize);
  481.     return nptr;
  482.     }
  483.  
  484. /* ARGSUSED */
  485. void myfree (ptr)
  486.     VOID *        ptr;
  487.     {
  488.     }
  489. #endif
  490.  
  491. static void readdict ()
  492.     {
  493.     struct dent        d;
  494.     register struct dent * dp;
  495.     struct dent *    lastdp;
  496.     char        lbuf[INPUTWORDLEN + MAXAFFIXLEN + 2 * MASKBITS];
  497.     char        ucbuf[INPUTWORDLEN + MAXAFFIXLEN + 2 * MASKBITS];
  498.     FILE *        dictf;
  499.     int            i;
  500.     int            h;
  501.  
  502.     if ((dictf = fopen (Dfile, "r")) == NULL)
  503.     {
  504.     (void) fprintf (stderr, BHASH_C_CANT_OPEN_DICT);
  505.     exit (1);
  506.     }
  507.  
  508.     hashtbl =
  509.       (struct dent *) calloc ((unsigned) hashsize, sizeof (struct dent));
  510.     if (hashtbl == NULL)
  511.     {
  512.     (void) fprintf (stderr, BHASH_C_NO_SPACE);
  513.     exit (1);
  514.     }
  515.  
  516.     i = 0;
  517.     while (fgets (lbuf, sizeof lbuf, dictf) != NULL)
  518.     {
  519.     if (!silent  &&  (i % 1000) == 0)
  520.         {
  521.         (void) fprintf (stderr, "%d ", i);
  522.         (void) fflush (stdout);
  523.         }
  524.     i++;
  525.  
  526.     if (makedent (lbuf, sizeof lbuf, &d) < 0)
  527.         continue;
  528.  
  529.     h = hash (strtosichar (d.word, 1), hashsize);
  530.  
  531.     dp = &hashtbl[h];
  532.     if ((dp->flagfield & USED) == 0)
  533.         {
  534.         *dp = d;
  535. #ifndef NO_CAPITALIZATION_SUPPORT
  536.         /*
  537.         ** If it's a followcase word, we need to make this a
  538.         ** special dummy entry, and add a second with the
  539.         ** correct capitalization.
  540.         */
  541.         if (captype (d.flagfield) == FOLLOWCASE)
  542.         {
  543.         if (addvheader (dp))
  544.           exit (1);
  545.         }
  546. #endif
  547.         }
  548.     else
  549.         {
  550.  
  551.         /*
  552.         ** Collision.  Skip to the end of the collision
  553.         ** chain, or to a pre-existing entry for this
  554.         ** word.  Note that d.word always exists at
  555.         ** this point.
  556.         */
  557.         (void) strcpy (ucbuf, d.word);
  558.         chupcase (ucbuf);
  559.         while (dp != NULL)
  560.         {
  561.         if (strcmp (dp->word, ucbuf) == 0)
  562.             break;
  563. #ifndef NO_CAPITALIZATION_SUPPORT
  564.         while (dp->flagfield & MOREVARIANTS)
  565.             dp = dp->next;
  566. #endif /* NO_CAPITALIZATION_SUPPORT */
  567.         dp = dp->next;
  568.         }
  569.         if (dp != NULL)
  570.         {
  571.         /*
  572.         ** A different capitalization is already in
  573.         ** the dictionary.  Combine capitalizations.
  574.         */
  575.         if (combinecaps (dp, &d) < 0)
  576.             exit (1);
  577.         }
  578.         else
  579.         {
  580.         /* Insert a new word into the dictionary */
  581.         for (dp = &hashtbl[h];  dp->next != NULL;  )
  582.             dp = dp->next;
  583.         lastdp = dp;
  584.         dp = (struct dent *) mymalloc (sizeof (struct dent));
  585.         if (dp == NULL)
  586.             {
  587.             (void) fprintf (stderr, BHASH_C_COLLISION_SPACE);
  588.             exit (1);
  589.             }
  590.         *dp = d;
  591.         lastdp->next = dp;
  592.         dp->next = NULL;
  593. #ifndef NO_CAPITALIZATION_SUPPORT
  594.         /*
  595.         ** If it's a followcase word, we need to make this a
  596.         ** special dummy entry, and add a second with the
  597.         ** correct capitalization.
  598.         */
  599.         if (captype (d.flagfield) == FOLLOWCASE)
  600.             {
  601.             if (addvheader (dp))
  602.               exit (1);
  603.             }
  604. #endif
  605.         }
  606.         }
  607.     }
  608.     if (!silent)
  609.     (void) fprintf (stderr, "\n");
  610.     (void) fclose (dictf);
  611.     }
  612.  
  613. static void newcount ()
  614.     {
  615.     char        buf[INPUTWORDLEN + MAXAFFIXLEN + 2 * MASKBITS];
  616. #ifndef NO_CAPITALIZATION_SUPPORT
  617.     ichar_t        ibuf[INPUTWORDLEN + MAXAFFIXLEN + 2 * MASKBITS];
  618. #endif
  619.     register FILE *    d;
  620.     register int    i;
  621. #ifndef NO_CAPITALIZATION_SUPPORT
  622.     ichar_t        lastibuf[sizeof ibuf / sizeof (ichar_t)];
  623.     int            headercounted;
  624.     int            followcase;
  625.     register char *    cp;
  626. #endif
  627.  
  628.     if (!silent)
  629.     (void) fprintf (stderr, BHASH_C_COUNTING);
  630.  
  631.     if ((d = fopen (Dfile, "r")) == NULL)
  632.     {
  633.     (void) fprintf (stderr, BHASH_C_CANT_OPEN_DICT);
  634.     exit (1);
  635.     }
  636.  
  637. #ifndef NO_CAPITALIZATION_SUPPORT
  638.     headercounted = 0;
  639.     lastibuf[0] = 0;
  640. #endif
  641.     for (i = 0;  fgets (buf, sizeof buf, d);  )
  642.     {
  643.     if ((++i % 1000) == 0  &&  !silent)
  644.         {
  645.         (void) fprintf (stderr, "%d ", i);
  646.         (void) fflush (stdout);
  647.         }
  648. #ifndef NO_CAPITALIZATION_SUPPORT
  649.     cp = index (buf, hashheader.flagmarker);
  650.     if (cp != NULL)
  651.         *cp = '\0';
  652.     if (strtoichar (ibuf, buf, INPUTWORDLEN * sizeof (ichar_t), 1))
  653.         (void) fprintf (stderr, WORD_TOO_LONG (buf));
  654.     followcase = (whatcap (ibuf) == FOLLOWCASE);
  655.     upcase (ibuf);
  656.     if (icharcmp (ibuf, lastibuf) != 0)
  657.         headercounted = 0;
  658.     else if (!headercounted)
  659.         {
  660.         /* First duplicate will take two entries */
  661.         if ((++i % 1000) == 0  &&  !silent)
  662.         {
  663.         (void) fprintf (stderr, "%d ", i);
  664.         (void) fflush (stdout);
  665.         }
  666.         headercounted = 1;
  667.         }
  668.     if (!headercounted  &&  followcase)
  669.         {
  670.         /* It's followcase and the first entry -- count again */
  671.         if ((++i % 1000) == 0  &&  !silent)
  672.         {
  673.         (void) fprintf (stderr, "%d ", i);
  674.         (void) fflush (stdout);
  675.         }
  676.         headercounted = 1;
  677.         }
  678.     (void) icharcpy (lastibuf, ibuf);
  679. #endif
  680.     }
  681.     (void) fclose (d);
  682.     if (!silent)
  683.     (void) fprintf (stderr, BHASH_C_WORD_COUNT, i);
  684.     if ((d = fopen (Cfile, "w")) == NULL)
  685.     {
  686.     (void) fprintf (stderr, CANT_CREATE, Cfile);
  687.     exit (1);
  688.     }
  689.     (void) fprintf (d, "%d\n", i);
  690.     (void) fclose (d);
  691.     }
  692.